package com.example.controller;

import com.example.entity.base.BaseResult;
import com.example.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.security.auth.message.AuthException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public abstract class BaseController {

    private final static Logger _log = LoggerFactory.getLogger(BaseController.class);

    /**
     * 向浏览器输出各异常的明细消息，未列出的异常将被屏蔽
     *
     * @param exception
     * @return
     */
    @ExceptionHandler
    public static BaseResult exceptionHandler(Exception exception) {
        _log.error("HTTP请求发生异常，", exception);
        if(exception instanceof AuthException){
            return BaseResult.newAuthError();
        }else if (exception instanceof IllegalArgumentException) {
            // 非法参数
            return BaseResult.newError(exception.getMessage());
        } else if (exception instanceof BindException) {
            // 参数绑定异常
            BindingResult bindingResult = ((BindException) exception).getBindingResult();
            StringBuilder errorMsg = getErrMsg(bindingResult);
            return BaseResult.newError(errorMsg.toString());
        } else if (exception instanceof MethodArgumentNotValidException) {
            // 参数绑定异常
            BindingResult bindingResult = ((MethodArgumentNotValidException) exception).getBindingResult();
            StringBuilder errorMsg = getErrMsg(bindingResult);
            return BaseResult.newError(errorMsg.toString());
        } else if (exception instanceof BusinessException) {
            // 参数绑定异常
            return BaseResult.newError(exception.getMessage());
        } else if (exception instanceof UnsupportedOperationException) {
            // 参数绑定异常
            return BaseResult.newError("UnsupportedOperationException：" + exception.getMessage());
        } /*else if (exception instanceof NullPointerException) {
            // 参数绑定异常
            return BaseResult.newError("NullPointerException：" + exception.getMessage());
        }*/
        // 其他异常，屏蔽
        return BaseResult.newError("服务器异常");

    }

    private static StringBuilder getErrMsg(BindingResult bindingResult) {
        StringBuilder errorMsg = new StringBuilder();
        if (bindingResult.hasErrors()) {
            List<ObjectError> errors = bindingResult.getAllErrors();
            for (ObjectError objectError : errors) {
                FieldError fieldError = (FieldError) objectError;
                if (_log.isDebugEnabled()) {
                    _log.error("Data check failure : object: " + fieldError.getObjectName() + ",field: " + fieldError.getField() + ",errorMessage: " + fieldError.getDefaultMessage());
                }
                errorMsg.append(objectError.getDefaultMessage());
                errorMsg.append(",");
            }
            errorMsg = new StringBuilder(errorMsg.substring(0, errorMsg.length() - 1));
        }
        return errorMsg;
    }


    public String getServerUrl(HttpServletRequest req) {
        String serverUrl = "";
        try {
            URL url = new URL(req.getRequestURL().toString());
            serverUrl = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return serverUrl;
    }

    public String getUserWebPath() throws IOException {
        Date date = new Date();
        String result = "upload";
        File dir = new File(result);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return result;
    }

    public void download(HttpServletResponse response, String recommendedName, String filePath) {
        download(response, recommendedName, filePath, true);
    }

    public void download(HttpServletResponse response, String recommendedName, String filePath,
                         boolean deleteAfterDownLoad) {
        FileInputStream fis = null;
        ServletOutputStream fout = null;

        if (filePath == null) {
            return;
        }

        File file = new File(filePath);
        try {
            if (!file.exists()) {
                PrintWriter out = response.getWriter();
                out.println("<SCRIPT LANGUAGE=\"JavaScript\">");
                out.println("<!--");
                out.println("   alert(\"此文件不存在或已经被删除!\");window.history.back(-1);");
                out.println("//-->");
                out.println("</SCRIPT>");
                return;
            }
            // 客户端显示的文件名
            recommendedName = new String(recommendedName.getBytes("GBK"), "ISO_8859_1");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + recommendedName + "\"");
            response.resetBuffer();

            fis = new FileInputStream(file);
            fout = response.getOutputStream();
            byte[] b = new byte[4096];
            while (fis.read(b) != -1) {
                fout.write(b);
                b = new byte[4096];
            }
            fout.flush();
        } catch (SocketException se) {
            // "取消导出导致错误,可忽略"
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
            if (fout != null) {
                try {
                    fout.close();
                } catch (IOException e) {
                }
            }
            // 是否下载完后,删除文件
            if (deleteAfterDownLoad) {
                file.delete();
            }
        }
    }

    public String getValue(HttpServletRequest request, String name) {
        String value = null;
        value = request.getParameter(name);
        if (value != null)
            return value;
        value = (String) request.getAttribute(name);
        if (value != null)
            return value;
        value = (String) request.getSession().getAttribute(name);
        request.getSession().removeAttribute(name);
        return value;
    }


    protected HttpServletRequest getRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        return servletRequestAttributes.getRequest();
    }

    private Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    private HashMap getParamMap(HttpServletRequest request) {
        Map<String, String[]> pm = request.getParameterMap();
        HashMap hm = new HashMap<>();
        for (String key : pm.keySet()) {
            hm.put(key, request.getParameter(key).toString());
        }
        return hm;
    }
}
